import threading
import time
# local modules
from .NSOde import NSOde
from .NSObject import NSObject
from .DerbyXML import DerbyXML
from .DerbyXML import Timer


class PeriodicTimer(threading.Thread):
    def __init__(self, interval, action):
        super(PeriodicTimer, self).__init__()
        self.interval = interval
        self.action = action
        self.running = False
        self.stopper = threading.Event()

    def StartTimer(self):
        if self.running:
            return
        self.running = True
        self.start()

    def StopTimer(self):
        if self.running:
            self.running = False
            self.stopper.set()

    def run(self):
        while not self.stopper.wait(self.interval):
            self.action(self)

    def IsRunning(self):
        return self.running


class Stopwatch(NSObject):
    """ A general purpose stop-watch like timer.  Timers start at 0:00.
            Start: Reset timer, starts
            Stop: Stops timer, holds time
            Resume: Resumes the timer, continue with time
            ResetTimer: Sets time back to 0:00, does not alter running status.
            Use 'addObserver' to watch the change of time """

    def __init__(self, interval=0.2, maximum=1e99, countsUp=True):
        NSObject.__init__(self)
        self.periodic = None
        self.interval = interval
        self.maximumTime = maximum
        self.elapsedTime = 0
        self.direction = countsUp
        self.startTime = 0

    def actionOrStop(self, timer):
        curtime = time.time() - self.startTime
        if curtime > self.maximumTime:
            curtime = self.maximumTime
        if curtime == self.maximumTime:
            self.StopTimer()
        self.elapsedTime = curtime  # we stop before we call the action so we can see if running there

    def StartTimer(self, startTime=0):
        self.ResetTimer(startTime)
        if not self.periodic:
            self.periodic = PeriodicTimer(self.interval, self.actionOrStop)
            self.periodic.StartTimer()

    def StopTimer(self):
        if self.periodic:
            self.periodic.StopTimer()
            self.periodic = None

    def ResumeTimer(self):
        if self.IsRunning():
            return
        # need to tweak with time before running
        self.startTime = time.time() - self.elapsedTime
        if not self.periodic:
            self.periodic = PeriodicTimer(self.interval, self.actionOrStop)
            self.periodic.StartTimer()

    def ResetTimer(self, startTime=0):
        self.startTime = time.time() - startTime
        self.elapsedTime = startTime

    def TimeLeft(self):
        return self.maximumTime - self.elapsedTime

    def FormattedTime(self):
        if self.direction:
            time = int(self.elapsedTime)
        else:
            time = int(self.maximumTime - self.elapsedTime)
        return Stopwatch.FormatTime(time)

    def IsRunning(self):
        return self.periodic and self.periodic.IsRunning()

    @classmethod
    def FormatTime(cls, time):
        if time > 60 * 60:
            return "%d:%.2d:%.2d" % (time / 3600, (time / 60) % 60, time % 60)
        else:
            return "%d:%.2d" % ( time / 60, time % 60)


class StopwatchSlave(NSObject):
    """ Nearly identical to the Stopwatch, but designed to just provide a backup
    stopwatch and instead watch an DerbyXML Timer """

    def __init__(self, timerDerbyXML):
        self.DerbyXML = timerDerbyXML

        def UpdateFromXML(obj, attr, value):
            pass

        timerDerbyXML.addObserver(UpdateFromXML, "duration")
        timerDerbyXML.addObserver(UpdateFromXML, "countsUp")
        timerDerbyXML.addObserver(UpdateFromXML, "text()")


class PeriodTimeFromFTDXML(object):
    def __init__(self, DerbyXML):
        self.isStopped = False
        self.ellapsedTime = 0
        # we want to watch the period, and the period
        def UpdatePeriods(obj, attrName, value):
            # find last active period
            activePeriod = None
            for period in self.DerbyXML.periods():
                if period.isActive:
                    activePeriod = period
            if activePeriod is None:
                self.isStopped = True
            else:
                self.ellapsedTime = 0
                lastTimestamp = None
                for event in activePeriod.events():
                    ts = event.timestamp
                    if ts is not None:
                        lastTimestamp = ts
                    if event.tag == "time-out" or event.tag == "official-review":
                        self.isStopped = True
                    else:
                        self.isStopped = False

        DerbyXML.addObserver(UpdatePeriods, "children()")
        for period in DerbyXML.periods():
            period.addObserver(UpdatePeriods, "start")
            period.addObserver(UpdatePeriods, "stop")
            period.addObserver(UpdatePeriods, "children()")


class JamTimeFromFTDXML(object):
    def __init__(self, DerbyXML):
        pass


class LineupTimeFromFTDXML(object):
    def __init__(self, DerbyXML):
        pass


class TimeoutTimeFromFTDXML(object):
    def __init__(self, DerbyXML):
        pass


class IntermissionTimeFromFTDXML(object):
    def __init__(self, DerbyXML):
        pass
